package com.zonski.jbots.desktop.client;

import java.awt.Component;
import java.awt.Image;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.PixelGrabber;
import java.awt.image.ImageObserver;
import java.awt.image.MemoryImageSource;
import java.awt.image.ColorModel;

import com.zonski.jbots.engine.Directions;

public class ImageUtilities
{
    /**
     * Rotates the image by 90 degrees with no loss of 
     * information
     */
    public static Image rotateImage90(Image image, Component component)
    {
        int width = image.getWidth(component);
        int height = image.getHeight(component);

        int[] pixels = new int[width * height];
        PixelGrabber grabber = new PixelGrabber(image, 0, 0, width, height, 
                pixels, 0, width);
        try
        {
            grabber.grabPixels();
        }catch(InterruptedException e){
            return createErrorImage(component, Color.GREEN);
        }

        int status = grabber.getStatus();
        if((status & ImageObserver.ABORT) != 0 &&
                (status & ImageObserver.ALLBITS) == 0)
        {
            return createErrorImage(component, Color.BLUE);
        }
        int newWidth = height;
        int newHeight = width;
        int[] newPixels = new int[newWidth * newHeight];
        int index = 0;
        for(int y = 0; y<height; y++)
        {
            for(int x = 0; x<width; x++)
            {
                int pixel = pixels[index];
                index++;
                int newX = y;
                int newY = width-x-1;
                newPixels[newY*newWidth + newX] = pixel;
            }
        }
        MemoryImageSource imageSource = new MemoryImageSource(
                newWidth, newHeight, newPixels, 0, newHeight
                );
        imageSource.setAnimated(false);
        Image newImage = component.createImage(imageSource);

        return newImage;
    }

    public static Image[][] createImages(Image[] northFacingImages, Image[] northEastFacingImages, Component component)
    {
        Image[][] images = new Image[Directions.MAX_DIRECTION+1][];
        images[Directions.NONE] = northFacingImages;
        images[Directions.SOUTH_EAST] = northEastFacingImages;
        images[Directions.SOUTH] = northFacingImages;
        for(int i=Directions.SOUTH; i!=Directions.EAST; )
        {
            i = Directions.addDirection(i, 1);
            int dir = Directions.addDirection(i, -2);
            images[i] = rotateImages90(images[dir], component);
        }
        return images;
    }

    public static Image[] rotateImages90(Image[] images, Component component)
    {
        Image[] rotated = new Image[images.length];
        //startLoading(images, component);
        for(int i=0; i<images.length; i++)
        {
            if(waitForImageData(images[i], component))
            {
                rotated[i] = rotateImage90(images[i], component);
            }else{
                rotated[i] = createErrorImage(component);
            }
        }
        return rotated;
    }

    public static Image flipImageVerticalAxis(Image image, Component component)
    {
        Image newImage;
        if(waitForImageData(image, component))
        {
            int width = image.getWidth(component);
            int height = image.getHeight(component);

            int[] pixels = new int[width * height];
            PixelGrabber grabber = new PixelGrabber(image, 0, 0, width, height,
                    pixels, 0, width);
            try
            {
                grabber.grabPixels();
            }catch(InterruptedException e){
                return createErrorImage(component, Color.ORANGE);
            }

            int status = grabber.getStatus();
            if((status & ImageObserver.ABORT) != 0 &&
                    (status & ImageObserver.ALLBITS) == 0)
            {
                return createErrorImage(component, Color.BLACK);
            }
            int[] newPixels = new int[width * height];
            int index = 0;
            for(int y = 0; y<height; y++)
            {
                for(int x = width; x>0; )
                {
                    x--;
                    int pixel = pixels[y*width + x];
                    newPixels[index] = pixel;
                    index++;
                }
            }
            MemoryImageSource imageSource = new MemoryImageSource(
                    width, height, newPixels, 0, width
                    );
            imageSource.setAnimated(false);
            newImage = component.createImage(imageSource);
        }else{
            newImage = createErrorImage(component);
        }
        return newImage;
    }

    public static Image recolorImage(Image image, Component component, Recolorer recolorer)
    {
        Image newImage;
        if(waitForImageData(image, component))
        {
            int width = image.getWidth(component);
            int height = image.getHeight(component);

            int[] pixels = new int[width * height];
            PixelGrabber grabber = new PixelGrabber(image, 0, 0, width, height,
                    pixels, 0, width);
            try
            {
                grabber.grabPixels();
            }catch(InterruptedException e){
                return createErrorImage(component, Color.ORANGE);
            }

            int status = grabber.getStatus();
            if((status & ImageObserver.ABORT) != 0 &&
                    (status & ImageObserver.ALLBITS) == 0)
            {
                return createErrorImage(component, Color.BLACK);
            }
            int[] newPixels = new int[width * height];
            int index = 0;
            for(int y = 0; y<height; y++)
            {
                for(int x = 0; x<width; x++)
                {
                    int pixel = pixels[index];
                    newPixels[index] = recolorer.recolor(pixel);
                    index++;
                }
            }
            MemoryImageSource imageSource = new MemoryImageSource(
                    width, height, newPixels, 0, width
                    );
            imageSource.setAnimated(false);
            newImage = component.createImage(imageSource);
        }else{
            newImage = createErrorImage(component);
        }
        return newImage;
    }

    public static boolean waitForImageData(Image image, Component component)
    {
        while(!component.prepareImage(image, component))
        {
            try
            {
                Thread.sleep(50);
            }catch(Exception e){
                return false;
            }
        }
        return true;
    }

    public static Image createErrorImage(Component component)
    {
        return createErrorImage(component, Color.RED);
    }
    
    public static Image createErrorImage(Component component, Color color)
    {
        Image image = component.createImage(10, 10);
        Graphics g = image.getGraphics();
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, 10, 10);
        g.setColor(color);
        g.drawRect(0, 0, 9, 9);
        g.drawLine(0, 0, 10, 10);
        g.drawLine(0, 10, 10, 0);
        g.dispose();
        return image;
    }

    public static void startLoading(Image[] images, Component component)
    {
        for(int i=0; i<images.length; i++)
        {
            component.prepareImage(images[i], component);
        }
    }
    
    private ImageUtilities()
    {
    }
}
